package com.example.component.others;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;

import com.example.hems.R;
import com.example.hems.utils.LogUtils;

/**
 * 縦用シックバーベース
 */
public class AbsVerticalSeekBar extends VerticalProgressBar {
    private Drawable mThumb;
    private int mThumbOffset;
    float mTouchProgressOffset;
    boolean mIsUserSeekable = true;
    private int mKeyProgressIncrement = 1;
    private static final int NO_ALPHA = 0xFF;
    private float mDisabledAlpha;

    /**
     * コンストラクタ
     * 
     * @param context
     */
    public AbsVerticalSeekBar(Context context) {
        super(context);
    }

    /**
     * コンストラクタ
     * 
     * @param context
     * @param attrs
     */
    public AbsVerticalSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * コンストラクタ
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    public AbsVerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.SeekBar, defStyle, 0);
        Drawable thumb = a.getDrawable(R.styleable.SeekBar_android_thumb);
        setThumb(thumb); 
        int thumbOffset =
                a.getDimensionPixelOffset(R.styleable.SeekBar_android_thumbOffset, getThumbOffset());
        setThumbOffset(thumbOffset);
        a.recycle();

        a = context.obtainStyledAttributes(attrs,
                R.styleable.Theme, 0, 0);
        mDisabledAlpha = a.getFloat(R.styleable.Theme_android_disabledAlpha, 0.5f);
        a.recycle();
    }

    /**
     * シックバーの矢印イメージを設定する
     * 
     * @param thumb
     */
    public void setThumb(Drawable thumb) {
        if (thumb != null) {
            thumb.setCallback(this);
            mThumbOffset = (int) thumb.getIntrinsicHeight() / 2;
        }
        mThumb = thumb;
        invalidate();
    }

    /**
     * 矢印のoffsetを取得する
     */
    public int getThumbOffset() {
        return mThumbOffset;
    }

    /**
     * 矢印のoffsetを設定する
     * 
     * @param thumbOffset
     */
    public void setThumbOffset(int thumbOffset) {
        mThumbOffset = thumbOffset;
        invalidate();
    }

    /**
     * 増加プログレスの値を設定する
     * 
     * @param increment
     */
    public void setKeyProgressIncrement(int increment) {
        mKeyProgressIncrement = increment < 0 ? -increment : increment;
    }

    /**
     * 増加プログレスの値を取得する
     */
    public int getKeyProgressIncrement() {
        return mKeyProgressIncrement;
    }

    @Override
    public synchronized void setMax(int max) {
        super.setMax(max);

        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
        }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return who == mThumb || super.verifyDrawable(who);
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();

        Drawable progressDrawable = getProgressDrawable();
        if (progressDrawable != null) {
            progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
        }

        if (mThumb != null && mThumb.isStateful()) {
            int[] state = getDrawableState();
            mThumb.setState(state);
        }
    }

    @Override
    void onProgressRefresh(float scale, boolean fromUser) {
        Drawable thumb = mThumb;
        if (thumb != null) {
            setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);
            invalidate();
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Drawable d = getCurrentDrawable();
        Drawable thumb = mThumb;
        int thumbWidth = thumb == null ? 0 : thumb.getIntrinsicWidth();
        int trackWidth = Math.min(mMaxWidth, w - getPaddingRight() - getPaddingLeft());
        int max = getMax();
        float scale = max > 0 ? (float) getProgress() / (float) max : 0;

        if (thumbWidth > trackWidth) {
            int gapForCenteringTrack = (thumbWidth - trackWidth) / 2;
            if (thumb != null) {
                setThumbPos(h, thumb, scale, gapForCenteringTrack * -1);
            }
            if (d != null) {
                d.setBounds(gapForCenteringTrack, 0,
                        w - getPaddingRight() - getPaddingLeft() - gapForCenteringTrack,
                        h - getPaddingBottom() - getPaddingTop());
            }
        } else {
            if (d != null) {
                d.setBounds(0, 0, w - getPaddingRight() - getPaddingLeft(), h - getPaddingBottom() - getPaddingTop());
            }
            int gap = (trackWidth - thumbWidth) / 2;
            if (thumb != null) {
                setThumbPos(h, thumb, scale, gap);
            }
        }
    }

    private void setThumbPos(int h, Drawable thumb, float scale, int gap) {
        int available = h - getPaddingTop() - getPaddingBottom();
        int thumbWidth = thumb.getIntrinsicWidth();
        int thumbHeight = thumb.getIntrinsicHeight();
        available -= thumbHeight;

        available += mThumbOffset * 2;
        int thumbPos = (int) ((1 - scale) * available);
        int leftBound, rightBound;
        if (gap == Integer.MIN_VALUE) {
            Rect oldBounds = thumb.getBounds();
            leftBound = oldBounds.left;
            rightBound = oldBounds.right;
        } else {
            leftBound = gap;
            rightBound = gap + thumbWidth;
        }

        thumb.setBounds(leftBound, thumbPos, rightBound, thumbPos + thumbHeight);
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mThumb != null) {
            canvas.save();
            canvas.translate(getPaddingLeft(), getPaddingTop() - mThumbOffset);
            mThumb.draw(canvas);
            canvas.restore();
        }
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Drawable d = getCurrentDrawable();

        int thumbWidth = mThumb == null ? 0 : mThumb.getIntrinsicWidth();
        int dw = 0;
        int dh = 0;
        if (d != null) {
            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
            dw = Math.max(thumbWidth, dh);
            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
        }
        dw += getPaddingLeft() + getPaddingRight();
        dh += getPaddingTop() + getPaddingBottom();

        LogUtils.e("TAG", "onMeasure()getPaddingTop()=" + getPaddingTop());
        
        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
                resolveSizeAndState(dh, heightMeasureSpec, 0));
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mIsUserSeekable || !isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setPressed(true);
            onStartTrackingTouch();
            trackTouchEvent(event);
            break;

        case MotionEvent.ACTION_MOVE:
            trackTouchEvent(event);
            attemptClaimDrag();
            break;

        case MotionEvent.ACTION_UP:
            trackTouchEvent(event);
            onStopTrackingTouch();
            setPressed(false);
            invalidate();
            break;

        case MotionEvent.ACTION_CANCEL:
            onStopTrackingTouch();
            setPressed(false);
            invalidate();
            break;
        }
        return true;
    }

    private void trackTouchEvent(MotionEvent event) {
        final int height = getHeight();
        final int available = height - getPaddingTop() - getPaddingBottom();
        int y = height - (int) event.getY();
        float scale;
        float progress = 0;
        if (y < getPaddingBottom()) {
            scale = 0.0f;
        } else if (y > height - getPaddingTop()) {
            scale = 1.0f;
        } else {
            scale = (float) (y - getPaddingBottom()) / (float) available;
            progress = mTouchProgressOffset;
        }

        final int max = getMax();
        progress += scale * max;

        setProgress((int) progress, true);
    }

    private void attemptClaimDrag() {
        if (getParent() != null) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
    }

    void onStartTrackingTouch() {
    }

    void onStopTrackingTouch() {
    }

    void onKeyChange() {
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        int progress = getProgress();

        switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_DOWN:
            if (progress <= 0)
                break;
            setProgress(progress - mKeyProgressIncrement, true);
            onKeyChange();
            return true;

        case KeyEvent.KEYCODE_DPAD_UP:
            if (progress >= getMax())
                break;
            setProgress(progress + mKeyProgressIncrement, true);
            onKeyChange();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

}
